/* 2014/10/28 */
package com.cosmos.log4j;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.helpers.LogLog;

/**
 * Provides function of compressing a single file to zip file.
 * 
 * @author Leonardo
 * 
 */
public class SingleFileZipper {

	/**
	 * Default buffer size is 1KB.
	 */
	protected int bufferSize = 1024;

	/**
	 * Compresses a single file to zip file with same file name (without
	 * extension).
	 * 
	 * @param file
	 *            file that to be compressed.
	 * @throws IOException
	 */
	public void zip(File file) throws IOException {
		// Generates zip file name.
		String zipFileName = null;
		String fileName = file.getName();
		int fileExtensionIndex = fileName.lastIndexOf(".");
		if (fileExtensionIndex == -1) {
			zipFileName = fileName + ".zip";
		} else {
			zipFileName = fileName.substring(0, fileExtensionIndex) + ".zip";
		}

		zip(file, zipFileName);
	}

	/**
	 * Compresses a single file to zip file with specified zip file name.
	 * 
	 * @param file
	 *            file that to be compressed.
	 * @param zipFileName
	 *            zip file name.
	 * @throws IOException
	 */
	public void zip(File file, String zipFileName) throws IOException {
		zip(file, file.getName(), zipFileName);
	}

	/**
	 * Compresses a single file to zip file with specified zip file name and
	 * file name inside zip file.
	 * 
	 * @param file
	 *            file that to be compressed.
	 * @param innerFileName
	 *            file name inside the zip file.
	 * @param zipFileName
	 *            zip file name.
	 * @throws IOException
	 */
	public void zip(File file, String innerFileName, String zipFileName)
			throws IOException {
		// Creates zip file.
		File zipFile = new File(file.getParent(), zipFileName);
		if (zipFile.exists()) {
			zipFile.delete();
		}
		try {
			zipFile.createNewFile();
		} catch (IOException ex) {
			throw new IOException("Creates zip file failed.", ex);
		}

		// Reads file and writes to zip file.
		FileOutputStream zipFileOutput = null;
		ZipOutputStream zipOutput = null;
		FileInputStream fileInput = null;
		int readLength = 0;
		byte[] buffer = new byte[bufferSize];
		try {
			zipFileOutput = new FileOutputStream(zipFile);
			zipOutput = new ZipOutputStream(zipFileOutput);
			zipOutput.putNextEntry(new ZipEntry(innerFileName));

			fileInput = new FileInputStream(file);
			while ((readLength = fileInput.read(buffer)) > 0) {
				zipOutput.write(buffer, 0, readLength);
			}
		} catch (IOException ex) {
			throw new IOException("Compresses file to zip failed.", ex);
		} finally {
			close(fileInput);
			close(zipOutput);
			close(zipFileOutput);
		}
	}

	private void close(Closeable resource) {
		if (resource != null) {
			try {
				resource.close();
			} catch (IOException ex) {
				LogLog.error("Closes resource failed.", ex);
			}
		}
	}
}
